package com.dming.auto.lib;

import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeSpec;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Calendar;

import javax.lang.model.element.Modifier;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

/**
 * Created by DMing at 2018/3/16 0016
 */

public class MvpXml {

    private String IBaseView = "com.dming.testjavapoet.framework.IBaseView";
    private String BaseRxPresenter = "com.dming.testjavapoet.framework.BaseRxPresenter";
    private String BaseRxActivity = "com.dming.testjavapoet.framework.BaseRxActivity";
    private String BaseRxFragment = "com.dming.testjavapoet.framework.BaseRxFragment";

    private String pkgName = "com.dming.testjavapoet";
    private String activityPath = "";
    private String fragmentPath = "";
    private String presenterPath = "";
    private String iViewPath = "";

    private String pkgPath;
    private String layoutPath;
    private String module;

    private boolean isActivity;

    private MvpXml(String module){
        if (module == null){
            this.module = "app";
        }
    }


    private void setPkgPath(){
//        String pkg = pkgName.replace(".",File.separator);
        File directory = new File("");//设定为当前文件夹
        try {
            pkgPath = directory.getCanonicalPath() + File.separator + module + "\\" + "src\\main\\java";
            layoutPath = directory.getCanonicalPath() + File.separator + module + "\\" + "src\\main\\res\\layout";
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("pkgPath: "+pkgPath);
    }

    public static MvpXml init(){
        return new MvpXml(null);
    }

    public static MvpXml init(String module){
        return new MvpXml(module);
    }

    public MvpXml setIBaseView(String iBaseView){
        this.IBaseView = iBaseView;
        return this;
    }

    public MvpXml setBaseRxPresenter(String baseRxPresenter){
        this.BaseRxPresenter = baseRxPresenter;
        return this;
    }

    public MvpXml setBaseRxActivity(String baseRxActivity){
        this.BaseRxActivity = baseRxActivity;
        return this;
    }
    public MvpXml setBaseRxFragment(String baseRxFragment){
        this.BaseRxFragment = baseRxFragment;
        return this;
    }

    public MvpXml setPkgName(String pkgName){
        this.pkgName = pkgName;
        return this;
    }

    public MvpXml setActivityPath(String activityPath){
        this.activityPath = "."+activityPath;
        return this;
    }
    public MvpXml setFragmentPath(String fragmentPath){
        this.fragmentPath = "."+fragmentPath;
        return this;
    }

    public MvpXml setPresenterPath(String presenterPath){
        this.presenterPath = "."+presenterPath;
        return this;
    }

    public MvpXml setIViewPath(String iViewPath){
        this.iViewPath = iViewPath;
        return this;
    }

    public void createMvp(String name,boolean isActivity){
        this.isActivity = isActivity;
        this.iViewPath = isActivity?activityPath+"."+iViewPath:fragmentPath+"."+iViewPath;
        setPkgPath();
        createActivityOrFragment(name,pkgPath);
        createRxPresenter(name,pkgPath);
        createIView(name,pkgPath);
        createLayout(name);
    }

    private String getCurTime(){
        Calendar calendar = Calendar.getInstance();
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH) + 1;
        int day = calendar.get(Calendar.DAY_OF_MONTH);
        return  year+"/"+month +"/"+day;
    }

    private String getLayoutName(String str){
        StringBuilder builder = new StringBuilder();
        char[] chars = str.toCharArray();
        for (int i = 0, length = chars.length; i < length; i++) {
            char c = chars[i];
            if (Character.isUpperCase(c)){
                builder.append('_');
                builder.append(Character.toLowerCase(c));
            }else {
                builder.append(c);
            }
        }
        return builder.toString();
    }

    private void createActivityOrFragment(String name,String filePath) {

        File file;
        if (isActivity) {
            file = new File(filePath, pkgName.replace(".", File.separator) + File.separator + activityPath.replace(".", File.separator) + File.separator + name + "Activity.java");
        }else {
            file = new File(filePath, pkgName.replace(".", File.separator) + File.separator + fragmentPath.replace(".", File.separator) + File.separator + name + "Fragment.java");
        }
        file.getParentFile().mkdirs();
        System.out.println("ActivityOrFragment: "+file);
        if (file.exists()){
            System.out.println("ActivityOrFragment File exists");
            return;
        }

        ClassName rxPresenter = ClassName.bestGuess(pkgName + presenterPath + "." + name + "RxPresenter");
        ClassName baseRxActivity = ClassName.bestGuess(BaseRxActivity);
        ClassName baseRxFragment = ClassName.bestGuess(BaseRxFragment);
        ClassName iView = ClassName.bestGuess(pkgName + iViewPath + ".I"+name + "View");
        ClassName r = ClassName.bestGuess(pkgName +".R");

        MethodSpec getLayoutResID = MethodSpec.methodBuilder("getLayoutResID")
                .addAnnotation(Override.class)
                .addModifiers(Modifier.PROTECTED)
                .returns(int.class)
                .addStatement("return $T.layout.$L$L",r, isActivity?"activity":"fragment",getLayoutName(name))
                .build();


        MethodSpec createPresenter = MethodSpec.methodBuilder("createPresenter")
                .addAnnotation(Override.class)
                .addModifiers(Modifier.PROTECTED)
                .returns(rxPresenter)
                .addStatement("return new $T(this)",rxPresenter)
                .build();


        TypeSpec activityOrFragment = TypeSpec.classBuilder(name + (isActivity?"Activity":"Fragment"))
                .addJavadoc(name + (isActivity?"Activity":"Fragment"))
                .addJavadoc("Created by DMing at "+getCurTime()+"\n")
                .addModifiers(Modifier.PUBLIC)
                .superclass(ParameterizedTypeName.get(isActivity?baseRxActivity:baseRxFragment, rxPresenter))
                .addSuperinterface(iView)
                .addMethod(getLayoutResID)
                .addMethod(createPresenter)
                .build();

        JavaFile javaFile = JavaFile.builder(pkgName+(isActivity?activityPath:fragmentPath), activityOrFragment)
                .build();

        try {
            javaFile.writeTo(new File(filePath));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void createRxPresenter(String name,String filePath) {

        File file = new File(filePath,pkgName.replace(".",File.separator) + File.separator + presenterPath.replace(".",File.separator) +File.separator+ name + "RxPresenter.java");
        file.getParentFile().mkdirs();
        System.out.println("Presenter: "+file);
        if (file.exists()){
            System.out.println("Presenter File exists");
            return;
        }

        ClassName iView = ClassName.bestGuess(pkgName + iViewPath + ".I"+name + "View");
        ClassName baseRxPresenter = ClassName.bestGuess(BaseRxPresenter);

        MethodSpec rxPresenter = MethodSpec.constructorBuilder()
                .addModifiers(Modifier.PUBLIC)
                .addParameter(iView, "iView")
                .addStatement("super(iView)")
                .build();

        TypeSpec presenter = TypeSpec.classBuilder(name + "RxPresenter")
                .addModifiers(Modifier.PUBLIC)
                .addJavadoc(name + "RxPresenter")
                .addJavadoc("Created by DMing at "+getCurTime()+"\n")
                .superclass(ParameterizedTypeName.get(baseRxPresenter, iView))
                .addMethod(rxPresenter)
                .build();

        JavaFile javaFile = JavaFile.builder(pkgName+presenterPath, presenter)
                .build();

        try {
            javaFile.writeTo(new File(filePath));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void createIView(String name,String filePath) {

        File file = new File(filePath,pkgName.replace(".",File.separator) + File.separator + iViewPath.replace(".",File.separator)+File.separator + "I"+name + "View.java");
        file.getParentFile().mkdirs();
        System.out.println("View: "+file);
        if (file.exists()){
            System.out.println("View File exists");
            return;
        }

        ClassName baseIView = ClassName.bestGuess(IBaseView);

        TypeSpec view = TypeSpec.interfaceBuilder("I"+name + "View")
                .addModifiers(Modifier.PUBLIC)
                .addJavadoc("I"+name + "View")
                .addJavadoc("Created by DMing at "+getCurTime()+"\n")
                .addSuperinterface(baseIView)
                .build();

        JavaFile javaFile = JavaFile.builder(pkgName+iViewPath, view)
                .build();
        try {
            javaFile.writeTo(new File(filePath));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void newLine(XMLStreamWriter xMLStreamWriter) throws XMLStreamException {
        xMLStreamWriter.writeCharacters("\n");
    }

    private void createLayout(String name){
        File file = new File(layoutPath,(isActivity?"activity":"fragment")+getLayoutName(name)+".xml");
        System.out.println("Layout: "+file);
        if (file.exists()){
            System.out.println("Layout File exists");
            return;
        }
        FileOutputStream outputStream = null;
        try {
            outputStream = new FileOutputStream(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        if (outputStream == null)return;
        try {
            XMLOutputFactory xMLOutputFactory = XMLOutputFactory.newInstance();
            XMLStreamWriter xMLStreamWriter = xMLOutputFactory.createXMLStreamWriter(outputStream);
            xMLStreamWriter.writeStartDocument("UTF-8", "1.0");
            newLine(xMLStreamWriter);

            xMLStreamWriter.writeStartElement("LinearLayout");
            xMLStreamWriter.writeAttribute("xmlns:android", "http://schemas.android.com/apk/res/android");
            xMLStreamWriter.writeAttribute("xmlns:tools","http://schemas.android.com/tools");
            xMLStreamWriter.writeAttribute("android:layout_width", "match_parent");
            xMLStreamWriter.writeAttribute("android:layout_height", "match_parent");
            xMLStreamWriter.writeAttribute("android:orientation", "vertical");

            newLine(xMLStreamWriter);
            xMLStreamWriter.writeEmptyElement("TextView");
            xMLStreamWriter.writeAttribute("android:layout_width", "match_parent");
            xMLStreamWriter.writeAttribute("android:layout_height", "match_parent");
            xMLStreamWriter.writeAttribute("android:gravity", "center");
            xMLStreamWriter.writeAttribute("tools:text", name);
//            xMLStreamWriter.writeEndElement();

            newLine(xMLStreamWriter);
            xMLStreamWriter.writeEndElement();

            xMLStreamWriter.writeEndDocument();

            xMLStreamWriter.flush();
            xMLStreamWriter.close();
        }catch (XMLStreamException e){
            e.printStackTrace();
        }
    }


    @Deprecated
    private void createLayoutXML(String name){
        File file = new File(layoutPath,"activity"+getLayoutName(name)+".xml");
        System.out.println("Layout: "+file);
        if (file.exists()){
            System.out.println("Layout File exists");
            return;
        }

        FileOutputStream outputStream = null;
        try {
            outputStream = new FileOutputStream(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        Document doc;
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        try {
            DocumentBuilder docBuilder = dbf.newDocumentBuilder();
            doc = docBuilder.newDocument();
            doc.setXmlStandalone(true);
            Element linearLayout = doc.createElement("LinearLayout");
            linearLayout.setAttribute(
                    "xmlns:android",
                    "http://schemas.android.com/apk/res/android");
            linearLayout.setAttribute(
                    "xmlns:tools",
                    "http://schemas.android.com/tools");
            doc.appendChild(linearLayout);

            linearLayout.setAttribute("android:layout_width", "match_parent");
            linearLayout.setAttribute("android:layout_height", "match_parent");
            linearLayout.setAttribute("android:orientation", "vertical");

            Element textView = doc.createElement("TextView");
            textView.setAttribute("android:layout_width", "match_parent");
            textView.setAttribute("android:layout_height", "match_parent");
            textView.setAttribute("tools:text", name);
            linearLayout.appendChild(textView);

            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer transformer = tf.newTransformer();
            transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            StreamResult xmlResult = new StreamResult(outputStream);
            transformer.transform(new DOMSource(doc), xmlResult);
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (TransformerConfigurationException e) {
            e.printStackTrace();
        } catch (TransformerException e) {
            e.printStackTrace();
        }
    }
}
